<?php

namespace addons\shopro\service\pay;

use think\Log;
use app\admin\model\shopro\Pay as PayModel;
use app\admin\model\shopro\user\User;
use app\admin\model\shopro\order\Action;
use think\helper\Str;
use addons\shopro\service\Wallet as WalletService;
use app\admin\model\shopro\Coupon;
use app\admin\model\shopro\user\Coupon as UserCouponModel;
use fast\Http;
use think\Db;


class PayOper
{
    protected $user = null;

    /**
     * 实例化
     *
     * @param mixed $user
     */
    public function __construct($user = null)
    {
        // 优先使用传入的用户
        $this->user = $user ? (is_numeric($user) ? User::get($user) : $user) : auth_user();
    }



    /**
     * 微信预付款
     *
     * @param think\Model $order
     * @param float $money
     * @param string $order_type
     * @return think\Model
     */
    public function wechat($order, $money, $order_type = 'order')
    {
        $pay = $this->addPay($order, [
            'order_type' => $order_type,
            'pay_type' => 'wechat',
            'pay_fee' => $money,
            'real_fee' => $money,
            'transaction_id' => null,
            'payment_json' => [],
            'status' => PayModel::PAY_STATUS_UNPAID
        ]);

        return $pay;
    }

    /**
     * 发放优惠券
     *
     * @param array|object $user 发放用户
     * @param array|object $coupon 要发放的优惠券
     * @param integer ucid 关联用户优惠券 //masks 新增 
     * @return array|object
     */
    private function send($user, $coupon, $ucid=0) {
        
        if ($coupon->get_status == 'cannot_get') {
            error_stop('您已经领取过了');
        }
        
        if ($coupon->stock <= 0) {
            error_stop('优惠券已经被领完了');
        }
		// p($coupon);

        $coupon->setDec('stock');

		// p($coupon);
        $userCoupon = new UserCouponModel();
        $userCoupon->user_id = $user->id;
        $userCoupon->coupon_id = $coupon->id;
        $userCoupon->use_time = null;
		if($ucid){
			$userCoupon->isact=0;
			$userCoupon->ucid=$ucid;
		}
        $userCoupon->save();

        return $userCoupon;
    }
    /**
     * 发放优惠券
     *
     * @param array|object $user 发放用户
     * @param array|object $coupon 要发放的优惠券
     * @param integer ucid 关联用户优惠券 //masks 新增 
     * @return array|object
     */
    private function send2($user, $coupon, $ucid=0) {
        
        if ($coupon->get_status == 'cannot_get') {
            return ;
        }
        
        if ($coupon->stock <= 0) {
            return ;
        }

        $coupon->setDec('stock');

		// p($coupon);
        $userCoupon = new UserCouponModel();
        $userCoupon->user_id = $user->id;
        $userCoupon->coupon_id = $coupon->id;
        $userCoupon->use_time = null;
		if($ucid){
			$userCoupon->isact=0;
			$userCoupon->ucid=$ucid;
		}
        $userCoupon->save();

        return $userCoupon;
    }
    /**
     * 支付宝预付款
     *
     * @param think\Model $order
     * @param float $money
     * @param string $order_type
     * @return think\Model
     */
    public function alipay($order, $money, $order_type = 'order')
    {
        $pay = $this->addPay($order, [
            'order_type' => $order_type,
            'pay_type' => 'alipay',
            'pay_fee' => $money,
            'real_fee' => $money,
            'transaction_id' => null,
            'payment_json' => [],
            'status' => PayModel::PAY_STATUS_UNPAID
        ]);

        return $pay;
    }



    /**
     * 余额付款
     *
     * @param think\Model $order
     * @param float $money
     * @param string $order_type
     * @return think\Model
     */
    public function money($order, $money, $order_type = 'order')
    {
        // 余额支付金额，传入金额和剩余支付金额最大值
        $money = $order->remain_pay_fee > $money ? $money : $order->remain_pay_fee;     // 混合支付不能超过订单应支付总金额

        // 扣除用户余额
        WalletService::change($this->user, 'money', -$money, 'order_pay', [
            'order_id' => $order->id,
            'order_sn' => $order->order_sn,
            'order_type' => $order_type,
        ]);

        // 添加支付记录
        $pay = $this->addPay($order, [
            'order_type' => $order_type,
            'pay_type' => 'money',
            'pay_fee' => $money,
            'real_fee' => $money,
            'transaction_id' => null,
            'payment_json' => [],
            'status' => PayModel::PAY_STATUS_PAID
        ]);
		// p($pay);die;

        // 余额直接支付成功，更新订单剩余应付款金额，并检测订单状态
        return $this->checkAndPaid($order, $order_type,'online',$pay);
    }



    /**
     * 积分支付
     *
     * @param think\Model $order
     * @param float $money
     * @param string $order_type
     * @return think\Model
     */
    public function score($order, $score, $order_type = 'order')
    {
        if ($order_type == 'order') {
            if ($order['type'] == 'score') {
                $log_type = 'score_shop_pay';
                $real_fee = $score;         // 积分商城真实抵扣，就是积分
            } else {
                $log_type = 'order_pay';
                // $real_fee = ;         // 积分商城真实抵扣，就是积分
                error_stop('缺少积分抵扣金额');       // 支持积分抵扣时补全
            }
        }

        WalletService::change($this->user, 'score', -$score, $log_type, [
            'order_id' => $order->id,
            'order_sn' => $order->order_sn,
            'order_type' => $order_type,
        ]);

        // 添加支付记录
        $pay = $this->addPay($order, [
            'order_type' => $order_type,
            'pay_type' => 'score',
            'pay_fee' => $score,
            'real_fee' => $real_fee,
            'transaction_id' => null,
            'payment_json' => [],
            'status' => PayModel::PAY_STATUS_PAID
        ]);

        // 积分直接支付成功，更新订单剩余应付款金额，并检测订单状态
        return $this->checkAndPaid($order, $order_type);
    }


    /**
     * 线下支付(货到付款)
     *
     * @param think\Model $order
     * @param float $money
     * @param string $order_type
     * @return think\Model
     */
    public function offline($order, $money, $order_type = 'order')
    {
        // 添加支付记录
        $pay = $this->addPay($order, [
            'order_type' => $order_type,
            'pay_type' => 'offline',
            'pay_fee' => $money,
            'real_fee' => $money,
            'transaction_id' => null,
            'payment_json' => [],
            'status' => PayModel::PAY_STATUS_PAID
        ]);

        // 更新订单剩余应付款金额，并检测订单状态
        return $this->checkAndPaid($order, $order_type, 'offline');
    }


    /**
     * 微信支付宝支付回调通用方法
     *
     * @param \think\Model $pay
     * @param array $notify
     * @return void
     */
    public function notify($pay, $notify)
    {
         Log::write('pay-notify-error:order notfound;pay111:' . json_encode($pay) . ';notify:' . json_encode($notify));
        $pay->status = PayModel::PAY_STATUS_PAID;
        $pay->transaction_id = $notify['transaction_id'];
        $pay->buyer_info = $notify['buyer_info'];
        $pay->payment_json = $notify['payment_json'];
        $pay->paid_time = time();
        $pay->save();

        $orderModel = $this->getOrderModel($pay->order_type);
        $order = new $orderModel();
        $order = $order->where('id', $pay->order_id)->find();
        if (!$order) {
            // 订单未找到，非正常情况，这里记录日志
            Log::write('pay-notify-error:order notfound;pay:' . json_encode($pay) . ';notify:' . json_encode($notify));
            return false;
        }

        if ($order->status == $order::STATUS_UNPAID) {      // 未支付，检测支付状态
            $order = $this->checkAndPaid($order, $pay->order_type);
        }

        return $order;
    }



    /**
     * 更新订单剩余应支付金额，并且检测订单状态
     *
     * @param think\Model $order
     * @param string $order_type
     * @return think\Model
     */
    public function checkAndPaid($order, $order_type, $pay_mode = 'online',$pay=false)
    {
        // Log::write('pay-notify-error:order notfound;paymode$order1:' . $order);
        // Log::write('pay-notify-error:order notfound;paymode$order_type:' . $order_type);
        // Log::write('pay-notify-error:order notfound;paymode:' . $pay_mode);
        // Log::write('pay-notify-error:order notfound;paymode$pay:' . $pay);
        // 获取订单已支付金额
        $payed_fee = $this->getPayedFee($order, $order_type);

        $remain_pay_fee = bcsub($order->pay_fee, (string)$payed_fee, 2);

        $order->remain_pay_fee = $remain_pay_fee;
        if ($remain_pay_fee <= 0) {
            $order->remain_pay_fee = 0;
            $order->paid_time = time();
            $order->status = $order::STATUS_PAID;
        } else {
            if ($pay_mode == 'offline') {
                // 订单未支付成功，并且是线下支付(货到付款)，将订单状态改为 pending
                $order->status = $order::STATUS_PENDING;
                $order->ext = array_merge($order->ext, ['pending_time' => time()]);     // 货到付款下单时间
                $order->pay_mode = 'offline';
            }
        }
        $order->save();

        if ($order->status == $order::STATUS_PAID) {
			//支付合并订单
			upMergeOrder([
				'id'=>$order->id,
				'money'=>$order->pay_fee,
			]);
			//masks 20240808 处理校园跑腿商品 生成跑腿订单 //需要有重量才能下跑腿单 @masks 20240826 跑腿订单加 upstair
			$ispaotui=0;
			$order_item=db('shopro_order_item')->where('order_id',$order->id)->select();//不直接用sum是怕以后有什么扩展处理
			// file_put_contents('./testapi.txt',date('Y-m-d H:i:s')."----订单产品：".json_encode($order_item)."\n",FILE_APPEND);
			foreach($order_item as $k=>$v){
				$goods_weight=$v['goods_weight']>0?$v['goods_weight']:1;
			// file_put_contents('./testapi.txt',date('Y-m-d H:i:s')."----订单产品12：".json_encode($goods_weight)."\n",FILE_APPEND);
			// file_put_contents('./testapi.txt',date('Y-m-d H:i:s')."----订单产品13：".json_encode($v['dispatch_type'])."\n",FILE_APPEND);
				if($v['dispatch_type']=='paotui')$ispaotui+=$goods_weight;
			// file_put_contents('./testapi.txt',date('Y-m-d H:i:s')."----订单产品11：".json_encode($ispaotui)."\n",FILE_APPEND);
			}
			$user = User::where('id', $order->user_id)->find();
			
			//2024.9.26 要发放的优惠券
			// 1.判断是否存在要自动发放的优惠券
			$coupon = Coupon::where(['get_start_time'=>['lt',time()],'get_end_time'=>['gt',time()],'is_auto_send'=>1,'stock'=>['gt',0],'use_scope'=>'category'])
			        ->whereNull('deletetime')
			        ->select();
		    
			foreach($coupon as $ck=>$cv){
			    //判断分类内是价格是否符合
			    $cateprice = 0;
			    foreach($order_item as $ok=>$ov){
			        $goodcate = Db::name('shopro_goods')->where(['id'=>$ov['goods_id']])->find();
			        
			        if($goodcate['category_ids'] == $cv['items']){
			            $cateprice = $cateprice + $ov['pay_fee'];
			        }
    			}
			    if($cateprice>=$cv['auto_send_price']){
			     //   $coupon2 = Coupon::normal()      // 正常的可以展示的优惠券
    				// 			->canGet()      // 在领取时间之内的
    				// 			->lock(true)
    				// 			->where('id', $cv['id'])
    				// 			->find();
    					
			        $this->send2($user, $cv);
			    }
			}
			
			
			// file_put_contents('./testapi.txt',date('Y-m-d H:i:s')."----订单产品1：".json_encode($ispaotui)."\n",FILE_APPEND);
			// p($ispaotui);die;
			if($ispaotui&&$order_type == 'order'){
				// $rtpt=$this->makePaotuiOrder($order,$ispaotui);
				$this->makePaotuiOrder($order,$ispaotui);
			// file_put_contents('./testapi.txt',date('Y-m-d H:i:s')."----订单产品2：".json_encode($rtpt)."\n",FILE_APPEND);
				// p($rtpt);die;
			}
			
            // 订单支付完成
            if ($order_type == 'order') {
                if ($pay_mode == 'offline') {
                    Action::add($order, null, auth_admin(), 'admin', '管理员操作自动货到付款支付成功');
                    // 在控制器执行后续内容，这里不再处理
                    return $order;
                } else {
                    Action::add($order, null, $user, 'user', '用户支付成功');
                    // 支付成功后续使用异步队列处理
                    \think\Queue::push('\addons\shopro\job\OrderPaid@paid', ['order' => $order, 'user' => $user], 'shopro-high');
                }
            } else if ($order_type == 'trade_order') {
                Log::write('pay-notify-error:order notfound;paymodeuser:' . $user);
				if($order['type']=="vip"){
					$ext = $order['ext'];
					$rule = $ext['rule'] ?? [];
					// $user=auth_user();
					if($rule['coupon_ids']){
    					$cids = explode(',',$rule['coupon_ids']);
    					foreach($cids as $id){
    						$coupon = Coupon::normal()      // 正常的可以展示的优惠券
    							->canGet()      // 在领取时间之内的
    							->lock(true)
    							->where('id', $id)
    							->find();
    						if (!$coupon) {
    				// 			error_stop('优惠券未找到');
    						}else{
    						    $this->send($user, $coupon);
    						}
    						
    					}
					}
					$days=$rule['days'];
					// p($days);die;
					
					if ($days > 0) {
						$nowdate=$user['vipend'] && $user['vipend']!='0000-00-00'?$user['vipend']:date('Y-m-d');
						if(strtotime($nowdate)>time()){
						    $afterdate=date('Y-m-d',strtotime($nowdate)+$days*86400);
						}else{
						    $afterdate=date('Y-m-d',time()+$days*86400);
						}
						
						db('user')->update(['id'=>$user['id'],'vipend'=>$afterdate,'updatetime'=>time()]);
					}
				}
                // 支付成功后续使用异步队列处理
                \think\Queue::push('\addons\shopro\job\trade\OrderPaid@paid', ['order' => $order, 'user' => $user], 'shopro-high');
            }
        } else if ($order->status == $order::STATUS_PENDING) {
            // 货到付款，添加货到付款队列（后续也需要处理拼团， 减库存等等）
            $user = User::where('id', $order->user_id)->find();
            if ($order_type == 'order') {
                Action::add($order, null, $user, 'user', '用户货到付款下单成功');

                // 支付成功后续使用异步队列处理
                \think\Queue::push('\addons\shopro\job\OrderPaid@offline', ['order' => $order, 'user' => $user], 'shopro-high');
            }
        }

		if($pay){
			$order->pay_sn=$pay->pay_sn;
			$order->pay_fee=$pay->pay_fee;
		}
        return $order;
    }



    /**
     * 获取订单已支付金额，商城订单 计算 积分抵扣金额
     *
     * @param \think\Model $order
     * @param string $order_type
     * @return string
     */
    public function getPayedFee($order, $order_type)
    {
        // 锁定读取所有已支付的记录，判断已支付金额
        $pays = PayModel::{'type' . Str::studly($order_type)}()->paid()->where('order_id', $order->id)->lock(true)->select();

        // 商城或者积分商城订单
        $payed_fee = '0';
        foreach ($pays as $key => $pay) {
            if ($pay->pay_type == 'score') {
                if ($order_type == 'order' && $order['type'] == 'goods') {
                    // 商城类型订单，并且不是积分商城订单，加上积分抵扣真实金额
                    $payed_fee = bcadd($payed_fee, $pay->real_fee, 2);
                } else {
                    // 其他类型，需要计算积分抵扣的金额时
                }
            } else {
                $payed_fee = bcadd($payed_fee, $pay->real_fee, 2);
            }
        }

        return $payed_fee;
    }



    /**
     * 获取剩余可退款的pays 记录（不含积分抵扣）
     * 
     * @param integer $order_id
     * @param string $sort  排序：money=优先退回余额支付的钱
     * @return \think\Collection
     */
    public function getCanRefundPays($order_id, $sort = 'money')
    {
        // 商城订单，已支付的 pay 记录, 这里只查 钱的支付记录，不查积分
        $pays = PayModel::typeOrder()->paid()->isMoney()->where('order_id', $order_id)->lock(true)->order('id', 'asc')->select();
        $pays = collection($pays);
        if ($sort == 'money') {
            // 对 pays 进行排序，优先退 money 的钱
            $pays = $pays->sort(function ($a, $b) {
                if ($a['pay_type'] == 'money' && $b['pay_type'] == 'money') {
                    return 0;
                } else if ($a['pay_type'] == 'money' && $b['pay_type'] != 'money') {
                    return -1;
                } else if ($a['pay_type'] != 'money' && $b['pay_type'] == 'money') {
                    return 1;
                } else {
                    return 0;
                }
            });

            $pays = $pays->values();
        }

        return $pays;
    }



    /**
     * 获取剩余可退款金额，不含积分相关支付
     *
     * @param mixed $pays
     * @return string
     */
    public function getRemainRefundMoney($pays)
    {
        // 拿到 所有可退款的支付记录
        $pays = ($pays instanceof \think\Collection) ? $pays : $this->getCanRefundPays($pays);

        // 支付金额，除了已经退完款的金额 （这里不退积分）
        $payed_money = (string)array_sum($pays->column('pay_fee'));
        // 已经退款金额 （这里不退积分）
        $refunded_money = (string)array_sum($pays->column('refund_fee'));
        // 当前剩余的最大可退款金额，支付金额 - 已退款金额
        $remain_max_refund_money = bcsub($payed_money, $refunded_money, 2);

        return $remain_max_refund_money;
    }



    /**
     * 添加 pay 记录
     *
     * @param think\Model $order
     * @param array $params
     * @return think\Model
     */
    public function addPay($order, $params)
    {
        $payModel = new PayModel();

        $payModel->order_type = $params['order_type'];
        $payModel->order_id = $order->id;
        $payModel->pay_sn = get_sn($this->user->id, 'P');
        $payModel->user_id = $this->user->id;
        $payModel->pay_type = $params['pay_type'];
        $payModel->pay_fee = $params['pay_fee'];
        $payModel->real_fee = $params['real_fee'];
        $payModel->transaction_id = $params['transaction_id'];
        $payModel->payment_json = $params['payment_json'];
        $payModel->paid_time = $params['status'] == PayModel::PAY_STATUS_PAID ? time() : null;
        $payModel->status = $params['status'];
        $payModel->refund_fee = 0;
        $payModel->save();

        return $payModel;
    }


    public function getOrderModel($order_type)
    {
        switch ($order_type) {
            case 'trade_order':
                $orderModel = '\\app\\admin\\model\\shopro\\trade\\Order';
                break;
            case 'order':
                $orderModel = '\\app\\admin\\model\\shopro\\order\\Order';
                break;
            default:
                $orderModel = '\\app\\admin\\model\\shopro\\order\\Order';
                break;
        }

        return $orderModel;
    }

	
    /**
     * 生成跑腿订单
     *
     * @param [type] $order
     * @param [type] $weight
     * @return string
     */
    public function makePaotuiOrder($order,$weight)
    {
		//只需要这些参数就可以了
		$data['isAddFromPay']=1;
		$data['shopro_order_id'] = $order['id'];
		$data['masks_user_id'] = $order['user_id'];
		$data['user_id'] = $order['user_id'];
		$data['upstairs'] = $order['upstair'];//20240826新增上楼
		$data['type'] = 1;
		$data['from_address_id'] = 1;//我把paotui_order_address的id为1的作为学校地址了
		//获取收货地址
		$address=db('shopro_order_address')->where('order_id',$order['id'])->find();
		$to_address=db('paotui_user_address')->where('user_id',$data['user_id'])->where('shopro_address_id',$address['shopro_address_id'])->order('is_default desc')->find();
		if(!$to_address)$to_address=db('paotui_user_address')->where('user_id',$data['user_id'])->order('is_default desc')->find();
		$data['to_address_id'] = $to_address['id'];//校园跑腿 商品下单时需要设置地址
		
		$gdt=db('paotui_goods_type')->where('id',1)->find();
		$goods_type=$gdt?$gdt['goods_type']:'代拿外卖';
		$data['goods_type'] = $goods_type;
		$data['weight'] = $weight;
			// file_put_contents('./testapi.txt',date('Y-m-d H:i:s')."----订单产品3：".json_encode($data)."\n",FILE_APPEND);
		
		// p($this->user);
		// $data['token']=$this->user->token;
		// Log::write('fasongjparams:' . json_encode($data) );
		//直接执行方法
		// $postController=new \app\api\controller\paotui\Post;
		// return $postController->add($data);
		Http::post('https://www.manchengsh.com/index.php/api/paotui.post/add',$data);
	}

}
